import ika
import direction
import map

class Entity(object):
    def __init__(self, x, y, layer):
        self.x = x
        self.y = y
        self.layer = layer
        self.z_index = 0
        self.direction = direction.left
        self.anim_state = "idle"
        self.anim_script = ""
        self.x_speed = 0
        self.y_speed = 0
        self.visible = True
        self.was_obstructed = False
        
    def GetIsObs(self):
        return 0
    def SetIsObs(self, value):
        pass
    def GetEntObs(self):
        return 0
    def SetEntObs(self, value):
        pass
    def GetMapObs(self):
        return 0
    def SetMapObs(self, value):
        pass
    def GetHotspotX(self):
        return 0
    def GetHotspotY(self):
        return 0
    def GetHotspotWidth(self):
        return 0
    def GetHotspotHeight(self):
        return 0
        
    # If you want an overriden method to by called by a property, you need
    # to wrap the function with a lambda. Ick! Lame.
    # Slightly better than redeclaring the properties in each inheriting class though.
    is_obstruction = property(lambda self: self.GetIsObs(), lambda self, value: self.SetIsObs(value))
    obstructed_by_entities = property(lambda self: self.GetEntObs(), lambda self, value: self.SetEntObs(value))
    obstructed_by_map = property(lambda self: self.GetMapObs(), lambda self, value: self.SetMapObs(value))
    hotspot_x = property(lambda self: self.GetHotspotX())
    hotspot_y = property(lambda self: self.GetHotspotY())
    hotspot_width = property(lambda self: self.GetHotspotWidth())
    hotspot_height = property(lambda self: self.GetHotspotHeight())
    
    def Draw(self, xwin, ywin):
        pass
            
    def Input(self, held, pressed):
        pass
        
    def Update(self):
        self.was_obstructed = False
        if self.x_speed != 0.0:
            xdist = self.MaxHorizontalDistance(self.x_speed)
            self.x += xdist
            if xdist != self.x_speed:
                self.was_obstructed = True
        if self.y_speed != 0.0:
            ydist = self.MaxVerticalDistance(self.y_speed)
            self.y += ydist
            if ydist != self.y_speed:
                self.was_obstructed = True
        
    def MaxHorizontalDistance(self, dist):
        if not self.obstructed_by_map:
            return dist
        max_dist = abs(dist)
        ey = int(self.y);
        for check in range(1, int(max_dist) + 2):
            if dist < 0:
                for y in range(ey, ey + self.hotspot_height):
                    if (map.map_engine.GetObsPixel (int(self.x - check), y, self.layer)
                            or map.map_engine.GetEntityObsPixel(self, int(self.x - check), y, self.layer)):
                        return -check + 1
            elif dist > 0:
                for y in range(ey, ey + self.hotspot_height):
                    if (map.map_engine.GetObsPixel (int(self.x + check - 1) + self.hotspot_width, y, self.layer)
                            or map.map_engine.GetEntityObsPixel(self, int(self.x + check - 1) + self.hotspot_width, y, self.layer)):
                        return check - 1
        return dist
        
    def MaxVerticalDistance(self, dist):
        if not self.obstructed_by_map:
            return dist
        max_dist = abs(dist);
        ex = int(self.x);
        for check in range(1, int(max_dist) + 2):
            if dist < 0:
                for x in range(ex, ex + self.hotspot_width):
                        if (map.map_engine.GetObsPixel (x, int(self.y - check), self.layer)
                                or map.map_engine.GetEntityObsPixel (self, x, int(self.y - check), self.layer)):
                            return -check + 1
            elif dist > 0:
                for x in range(ex, ex + self.hotspot_width):
                        if (map.map_engine.GetObsPixel (x, int(self.y + check - 1) + self.hotspot_height, self.layer)
                                or map.map_engine.GetEntityObsPixel (self, x, int(self.y + check - 1) + self.hotspot_height, self.layer)):
                            return check - 1;
        return dist
        
    def CollidesWith(self, x, y, x2, y2):
        "Tests whether or not this entity collides with the specified rectangular region. Returns true if they collide."
        if (self.x + self.hotspot_width >= x
                and self.x <= x2
                and self.y + self.hotspot_height >= y
                and self.y <= y2):
            return True
        return False
    
        
        
class IkaEntity(Entity):
    def __init__(self, x, y, layer, filename):
        Entity.__init__(self, x, y, layer)
        self.ika_entity = ika.Entity(x, y, layer, filename)
        # Hide the actual entity off-screen so we can override the ika.Entity rendering
        self.ika_entity.x = -self.ika_entity.hotwidth
        self.ika_entity.y = -self.ika_entity.hotheight
    
    def GetIsObs(self):
        return self.ika_entity.isobs
    def SetIsObs(self, value):
        self.ika_entity.isobs = value
    def GetEntObs(self):
        return self.ika_entity.entobs
    def SetEntObs(self, value):
        self.ika_entity.entobs = value
    def GetMapObs(self):
        return self.ika_entity.mapobs
    def SetMapObs(self, value):
        self.ika_entity.mapobs = value
    def GetHotspotX(self):
        return self.ika_entity.hotx
    def GetHotspotY(self):
        return self.ika_entity.hoty
    def GetHotspotWidth(self):
        return self.ika_entity.hotwidth
    def GetHotspotHeight(self):
        return self.ika_entity.hotheight
        
    def Draw(self, xwin, ywin):
        x = self.x - xwin
        y = self.y - ywin
        if self.ika_entity != None:
            self.ika_entity.Draw(int(x) - self.ika_entity.hotx, int(y) - self.ika_entity.hoty)
            
    def Update(self):
        s = self.ika_entity.GetAnimScript(self.anim_state + "_" + self.direction.name)
        #print self.anim_state + "_" + self.direction.name
        if s != self.anim_script:
            self.anim_script = s
            self.ika_entity.specanim = self.anim_script
        
        self.ika_entity.Update()
        super(IkaEntity, self).Update()